package cn.coufran.springboot.starter.json;

import com.alibaba.fastjson2.filter.ValueFilter;
import com.alibaba.fastjson2.util.TypeUtils;

import java.util.*;

/**
 * Hibernate lazy load属性过滤
 * <p>
 * 对于Hibernate lazy load属性，如果未加载，替换为null
 * </p>
 * @author Coufran
 * @version 1.0.0
 * @since 1.0.0
 */
public class HibernateValueFilter implements ValueFilter {
    /** 默认实例 */
    public static final HibernateValueFilter INSTANCE = new HibernateValueFilter();

    /** 代理类 */
    private static Collection<String> proxyClassNames = new TreeSet<>();
    /** 代理类接口 */
    private static Collection<String> proxyInterfaceNames = new TreeSet<>();

    static {
        HibernateValueFilter.addProxyClassName("org.hibernate.collection.internal.PersistentBag");
    }

    /**
     * 添加需要过滤的代理类
     * @param proxyClassName 代理类全限定名
     */
    public static void addProxyClassName(String proxyClassName) {
        proxyClassNames.add(proxyClassName);
    }

    /**
     * 添加需要过滤的接口
     * @param proxyInterfaceName 接口全限定名
     */
    public static void addProxyInterfaceName(String proxyInterfaceName) {
        proxyInterfaceNames.add(proxyInterfaceName);
    }

    /**
     * 过滤Hibernate lazy load属性，未加载的直接替换为null
     * @param object 序列化对象
     * @param name 属性名
     * @param value 属性值
     * @return 转换后的属性值
     */
    @Override
    public Object apply(Object object, String name, Object value) {
        if (value != null && this.isProxy(value.getClass()) && !HibernateUtils.isInitialized(value)) {
            return null;
        }
        return value;
    }

    /**
     * 类是不是代理类
     * @param clazz 类
     * @return 是代理类返回true
     */
    private boolean isProxy(Class<?> clazz) {
        // class判断
        if (!proxyClassNames.isEmpty()) {
            String className = clazz.getName();
            if (proxyClassNames.contains(className)) {
                return true;
            }
        }
        // interface判断
        if (!proxyInterfaceNames.isEmpty()) {
            Class<?>[] interfaces = clazz.getInterfaces();
            for (Class<?> interface_ : interfaces) {
                String interfaceName = interface_.getName();
                if (proxyInterfaceNames.contains(interfaceName)) {
                    return true;

                }
            }
        }
        // Fastjson原生判定
        if (TypeUtils.isProxy(clazz)) {
            return true;
        }
        return false;
    }
}
